class Solution {
public:
    struct Unionfind
    {
        vector<int> parent;
        Unionfind(int n)
        {
            parent.resize(n, -1);
        }
        int find(int x)
        {
            vector<int> son;
            while (parent[x] >= 0)
            {
                son.push_back(x);
                x = parent[x];
            }
            for (auto e : son)parent[e] = x;
            return x;
        }

        void merge(int x, int y)
        {
            int rootx = find(x);
            int rooty = find(y);
            if (rootx == rooty)return;
            if (abs(parent[rootx]) < abs(parent[rooty]))
            {
                swap(rootx, rooty);
            }
            parent[rootx] += parent[rooty];
            parent[rooty] = rootx;
        }

        int size()
        {
            int cnt = 0;
            for (auto e : parent)if (e < 0)cnt++;
            return cnt;
        }
    };

    bool check(string& x, string& y)
    {
        int cnt = 0;
        for (int i = 0; i < x.size(); i++)
        {
            if (x[i] != y[i])
            {
                cnt++;
                if (cnt > 2) return false;
            }
        }
        return true;
    }
    int numSimilarGroups(vector<string>& strs)
    {
        int m = strs.size();
        Unionfind uf(m);
        for (int i = 0; i < m; i++)
        {
            for (int j = i + 1; j < m; j++)
            {
                if (check(strs[i], strs[j]) == true)
                {
                    uf.merge(i, j);
                }
            }
        }

        return uf.size();
    }
};